package cn.sdack.go.users.service;

import cn.sdack.go.common.entities.users.RegionEntity;
import cn.sdack.go.users.dao.RegionDao;
import jakarta.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * @author sdack
 * @date 2024/2/22
 */
@Service
public class RegionServiceImpl implements RegionService {

    @Autowired
    private RegionDao regionDao;


    @Override
    public Page<RegionEntity> queryPage(RegionEntity parma, Integer page, Integer pageSize) throws Exception {
        return null;
    }

    @Override
    public RegionEntity getByCode(Long code, boolean isChild) throws Exception {
        RegionEntity entity = regionDao.findByCodeAndDelIsNull(code);
        if (entity == null) {
            throw new IllegalAccessException("non-existent");
        }
        if (isChild) {
            List<RegionEntity> child = this.loadChild(entity);
            entity.setChild(child);
        }
        return entity;
    }

    @Override
    public RegionEntity getById(Long id, boolean isChild) throws Exception {
        Optional<RegionEntity> optional = regionDao.findById(id);
        if (optional.isEmpty()) {
            throw new IllegalAccessException("non-existent");
        }
        RegionEntity entity = optional.get();
        if (isChild) {
            List<RegionEntity> child = this.loadChild(entity);
            entity.setChild(child);
        }
        return entity;
    }

    @Override
    public List<RegionEntity> getByLevel(Integer level, boolean isChild) throws Exception {
        List<RegionEntity> all = regionDao.findAllByLevelAndDelIsNull(level);
        if (isChild) {
            for (RegionEntity entity : all) {
                List<RegionEntity> child = this.loadChild(entity);
                entity.setChild(child);
            }
        }
        return all;
    }


    @Transactional
    @Override
    public RegionEntity add(RegionEntity param) throws Exception {
        param.setId(null);
        long id = 1001L;
        Integer level = param.getLevel();
        if (level == -1) {
            Page<RegionEntity> page = regionDao.findAllByLevelAndDelIsNull(0, PageRequest.of(0, 1, Sort.by(Sort.Order.asc("id"))));
            if (page.isEmpty()) {
                id = 1000;
            } else {
                RegionEntity entity = page.getContent().get(0);
                if (entity.getId() == 1000) {
                    id = 1L;
                } else {
                    id = entity.getId() + 1;
                }
            }
            param.setLevel(0);
            param.setPid(0L);
            param.setPcode(0L);
            param.setCode(id+1000);
        } else {
            Page<RegionEntity> page = regionDao.findAll(PageRequest.of(0, 1, Sort.by(Sort.Order.desc("id"))));
            if (!page.isEmpty()) {
                id = page.getContent().get(0).getId() + 1;
            }
        }
        param.setId(id);

        if (param.getPid() > 0) {
            RegionEntity pentity = getById(param.getId(), false);
            param.setLevel(pentity.getLevel()+1);
            param.setPcode(pentity.getCode());
        }

        return regionDao.save(param);
    }

    @Transactional
    @Override
    public RegionEntity edit(RegionEntity param) throws Exception {
        RegionEntity entity = getById(param.getId(), false);
        if (param.getCode() > 0) {
            entity.setCode(param.getCode());
        }
        if (StringUtils.hasLength(param.getName())) {
            entity.setName(param.getName());
        }
        entity.setCode(param.getCode());

        return regionDao.save(entity);
    }

    @Transactional
    @Override
    public RegionEntity del(Long id, boolean isChild) throws Exception {
        RegionEntity entity = getById(id, false);
        if (entity.getDel() != null) {
            return entity;
        }
        LocalDateTime now = LocalDateTime.now();
        entity.setDel(now);
        if (isChild) {
            RegionEntity entity1 = getById(id, isChild);
            this.delChild(entity1,now);
        }
        return regionDao.save(entity);
    }


    private List<RegionEntity> loadChild(RegionEntity parent) {
        List<RegionEntity> list = regionDao.findAllByPidAndDelIsNull(parent.getId());
        for (RegionEntity entity : list) {
            List<RegionEntity> list1 = loadChild(entity);
            entity.setChild(list1);
        }
        parent.setChild(list);
        return list;
    }

    private void delChild(RegionEntity parent,LocalDateTime now) {
        List<RegionEntity> child = parent.getChild();
        child.forEach(it -> it.setDel(now));
        regionDao.saveAll(child);
        for (RegionEntity entity : child) {
            this.delChild(entity,now);
        }
    }

}
